/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { ArkFile, ts } from 'arkanalyzer';
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from '../BaseChecker';
import { Rule, Defects, MatcherTypes, MatcherCallback, FileMatcher } from '../../Index';
import { RuleListUtil } from "../../utils/common/DefectsList";
import { IssueReport } from '../../model/Defects';

const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'NoUselessCatchCheck');
interface Violation {
    line: number;
    character: number;
    message: string;
    filePath?: string,
}

export class NoUselessCatchCheck implements BaseChecker {
    public rule: Rule;
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];
    public metaData: BaseMetaData = {
        severity: 2,
        ruleDocPath: 'docs/no-useless-catch-check.md',
        description: 'Disallow unnecessary catch clauses.',
    };

    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    public registerMatchers(): MatcherCallback[] {
        const fileMatcher: MatcherCallback = {
            matcher: this.fileMatcher,
            callback: this.check,
        };
        return [fileMatcher];
    }

    public check = (target: ArkFile) => {
        if (target instanceof ArkFile) {
            let code = target.getCode();
            const myInvalidPositions = this.checkAction(code);
            myInvalidPositions.forEach((violation) => {
                violation.filePath = target.getFilePath();
                this.addIssueReport(violation);
            });
        }
    };

    private checkAction(sourceCode: string): Violation[] {
        // 解析代码段为AST树对象
        const sourceFile = ts.createSourceFile(
            "temp.ts",
            sourceCode,
            ts.ScriptTarget.Latest,
            true
        );
        const violations: Violation[] = [];

        function checkNode(node: ts.Node) {
            if (ts.isCatchClause(node)) {
                if (node.block.statements.length === 1) {
                    const stmt = node.block.statements[0];
                    if (ts.isThrowStatement(stmt) && stmt.expression && ts.isIdentifier(stmt.expression)) {
                        const catchVariable = node.variableDeclaration?.name;
                        if (catchVariable && ts.isIdentifier(catchVariable) && stmt.expression.text === catchVariable.text) {
                            const parentTryStatement = node.parent;
                            if (ts.isTryStatement(parentTryStatement) && parentTryStatement.finallyBlock) {
                                const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
                                violations.push({
                                    message: 'Unnecessary catch clause.',
                                    line: line + 1,
                                    character: character + 1
                                });
                            } else {
                                const { line, character } = sourceFile.getLineAndCharacterOfPosition(parentTryStatement.getStart());
                                violations.push({
                                    message: 'Unnecessary try/catch wrapper.',
                                    line: line + 1,
                                    character: character + 1
                                });
                            }
                        }
                    }
                }
            }
            // 循环调用，遍历整个文件中的代码段
            ts.forEachChild(node, checkNode);

        }
        checkNode(sourceFile);
        return violations;
    }

    private addIssueReport(violation: Violation) {
        this.metaData.description = violation.message;
        const severity = this.rule.alert ?? this.metaData.severity;
        const fixKey = violation.line + '%' + violation.character + '%' + this.rule.ruleId;
        const mergeKey = violation.filePath + '%' + fixKey + '%' + this.metaData.description;
        const defect = new Defects(violation.line, violation.character, this.metaData.description, severity,
            this.rule.ruleId, mergeKey, this.metaData.ruleDocPath, true, false, false, fixKey);
        this.issues.push(new IssueReport(defect, undefined));
        RuleListUtil.push(defect);
    }
}
